﻿//
// (C) Copyright 2009 Irantha Suwandarathna (iranthas@hotmail.com)
// All rights reserved.
//

/********************************************************
 * ADO.NET 2.0 Data Provider for SQLite Version 3.X
 * Written by Robert Simpson (robert@blackcastlesoft.com)
 * 
 ********************************************************/

#if !PLATFORM_COMPACTFRAMEWORK
using System;
using System.Data;
using System.Data.Common;
using System.Transactions;

namespace System.Data.EffiProz
{
    internal class EfzEnlistment : IEnlistmentNotification
    {
        private EfzTransaction _transaction;
        private Transaction _scope;        
        private EfzConnectionProxy _connectionProxy;

        internal EfzTransaction dbTransaction
        {
            get{ return _transaction;}
            set { _transaction = value; }
        }

        internal bool DisposeConnection { get; set; }

        internal Transaction Scope { get { return _scope; } }

        internal bool IsCompleted
        {
            get
            {
                return _transaction == null;
            }
        }

        internal EfzEnlistment(EfzConnectionProxy connectionProxy, Transaction scope)
        {
            _scope = scope;
            _connectionProxy = connectionProxy;

            IsolationLevel isoLevel = IsolationLevel.ReadCommitted;
            switch (_scope.IsolationLevel)
            {
                case System.Transactions.IsolationLevel.ReadCommitted:
                    isoLevel = IsolationLevel.ReadCommitted;
                    break;
                case System.Transactions.IsolationLevel.ReadUncommitted:
                    isoLevel = IsolationLevel.ReadUncommitted;
                    break;
                case System.Transactions.IsolationLevel.RepeatableRead:
                    isoLevel = IsolationLevel.RepeatableRead;
                    break;
                case System.Transactions.IsolationLevel.Serializable:
                    isoLevel = IsolationLevel.Serializable;
                    break;
                case System.Transactions.IsolationLevel.Snapshot:
                    isoLevel = IsolationLevel.Snapshot;
                    break;
                case System.Transactions.IsolationLevel.Unspecified:
                    isoLevel = IsolationLevel.Unspecified;
                    break;
                case System.Transactions.IsolationLevel.Chaos:
                    isoLevel = IsolationLevel.Chaos;
                    break;

            }

            _transaction = _connectionProxy.BeginTransaction(isoLevel);
            _scope = scope;

            _scope.EnlistVolatile(this, System.Transactions.EnlistmentOptions.None);
        }

        private void Cleanup(EfzConnectionProxy cnn)
        {
            if (DisposeConnection || (!cnn.IsPooled && ( cnn.Owner == null || cnn.Owner.IsClosed )))
                cnn.Close();

            _transaction = null;
            _scope = null;
            _connectionProxy = null;
        }

        #region IEnlistmentNotification Members

        public void Commit(Enlistment enlistment)
        {
            if (_transaction != null && !_transaction.IsCompleted)
            {           
                _connectionProxy.Enlistment = null;

                try
                {
                    _transaction.IsValid(true);                 
                    _transaction.Commit();                 
                    enlistment.Done();
                }
                finally
                {
                    Cleanup(_connectionProxy);
                }
            }           
        }

        public void InDoubt(Enlistment enlistment)
        {
            enlistment.Done();
        }

        public void Prepare(PreparingEnlistment preparingEnlistment)
        {
            if (_transaction != null && !_transaction.IsCompleted)
            {
                if (_transaction.PrepareCommit() == false)
                    preparingEnlistment.ForceRollback();
                else
                    preparingEnlistment.Prepared();
            }
        }

        public void Rollback(Enlistment enlistment)
        {
            if (_transaction != null && !_transaction.IsCompleted)
            {              
                _connectionProxy.Enlistment = null;

                try
                {
                    _transaction.Rollback();
                    enlistment.Done();
                }
                finally
                {
                    Cleanup(_connectionProxy);
                }
            }
        }

        #endregion
    }
}
#endif